package fun.codedesign.jdk.math.fizzbuzz;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

public class FizzBuzz {
    /**
     * 打印输出1到n之间的数字，将3的倍数替换为String Fizz 5的倍数替换为 Buzz 15的倍数替换为FizzBuzz
     */
    public static void main(String[] args) {
        // 抽象后的方法比不抽象的更耗时，但扩展性好
        long l1 = System.currentTimeMillis();
        System.out.println(fizzBuzz(100000).toString());
        long l2 = System.currentTimeMillis();
        System.out.println(l2 - l1);
        long l3 = System.currentTimeMillis();
        System.out.println(alternativeFizzBuzz(100000).toString());
        long l4 = System.currentTimeMillis();
        System.out.println(l4 - l3);
    }

    /**
     * if else 语句判断
     * <p>if else 语句中如果 if第一个条件为true，则 else if 或者else 都不执行</p>
     * <p>
     * 时间复杂度 O(n)
     * 空间复杂度 O(1)
     *
     * @param n
     * @return
     */
    public static List<String> fizzBuzz(final int n) {
        List<String> list = new ArrayList<>(n);
        for (int i = 1; i < n + 1; i++) {
            // 先 % 15，因为%15的都可以%3 和 %5
            if (i % 15 == 0) {
                list.add("FizzBuzz");
            } else if (i % 3 == 0) {
                list.add("Fizz");
            } else if (i % 5 == 0) {
                list.add("Buzz");
            } else {
                // 此处使用Integer.toString(n),n==null会报空指针异常,如果使用String.valueOf(n)针对n为null时不报NOP
                list.add(Integer.toString(i));
            }
        }
        return list;
    }

    /**
     * 经过抽象后的方法，不仅适用于3，5 替换Fizz Buzz的情况，而且适用于替换从其他字符的方法
     * <p>抽象的toWord的方法能适用于其他情况</p>
     * 时间复杂度 O(n) 比以上多一重判断,实际上是O(2n)
     * 空间复杂度 O(1)
     *
     * @param n
     * @return
     */
    public static List<String> alternativeFizzBuzz(final int n) {
        List<String> list = new ArrayList<String>(n);
        for (int i = 1; i <= n; i++) {
            final String word = toWord(3, i, "Fizz") + toWord(5, i, "Buzz");
            if (StringUtils.isEmpty(word)) {
                list.add(Integer.toString(i));
            } else {
                list.add(word);
            }
        }
        return list;
    }

    private static String toWord(final int divisor, final int value,
                                 final String word) {
        return value % divisor == 0 ? word : "";
    }

    @Test
    public void testFizzBuzz() throws Exception {
        long l1 = System.currentTimeMillis();
        System.out.println(fizzBuzz(100000).toString());
        long l2 = System.currentTimeMillis();
        System.out.println(l2 - l1);
    }

    @Test
    public void testAlternativeFizzBuzz() throws Exception {
        long l3 = System.currentTimeMillis();
        System.out.println(alternativeFizzBuzz(100000).toString());
        long l4 = System.currentTimeMillis();
        System.out.println(l4 - l3);
    }

}
